/*FreeMind - A Program for creating and viewing Mindmaps
 *Copyright (C) 2000-2001  Joerg Mueller <joergmueller@bigfoot.com>
 *See COPYING for Details
 *
 *This program is free software; you can redistribute it and/or
 *modify it under the terms of the GNU General Public License
 *as published by the Free Software Foundation; either version 2
 *of the License, or (at your option) any later version.
 *
 *This program is distributed in the hope that it will be useful,
 *but WITHOUT ANY WARRANTY; without even the implied warranty of
 *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *GNU General Public License for more details.
 *
 *You should have received a copy of the GNU General Public License
 *along with this program; if not, write to the Free Software
 *Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
/*$Id: MindMapNodeModel.java,v 1.21.14.4.4.11 2008/05/26 19:25:09 christianfoltin Exp $*/

package freemind.modes.mindmapmode;

import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.ListIterator;

import freemind.main.FreeMindMain;
import freemind.main.HtmlTools;
import freemind.modes.MindMap;
import freemind.modes.NodeAdapter;

/**
 * This class represents a single Node of a Tree. It contains direct handles to
 * its parent and children and to its view.
 */
public class MindMapNodeModel extends NodeAdapter {

    //
    // Constructors
    //

    public MindMapNodeModel(FreeMindMain frame, MindMap map) {
        this(null, frame, map);
    }

    public MindMapNodeModel(Object userObject, FreeMindMain frame, MindMap map) {
        super(userObject, frame, map);
        children = new LinkedList();
        setEdge(new MindMapEdgeModel(this, getFrame()));
    }

    //
    // The mandatory load and save methods
    //

    public String getPlainTextContent() {
        return HtmlTools.htmlToPlain(toString());
    }

    public void saveTXT(Writer fileout, int depth) throws IOException {
        String plainTextContent = getPlainTextContent();
        for (int i = 0; i < depth; ++i) {
            fileout.write("    ");
        }
        if (plainTextContent.matches(" *")) {
            fileout.write("o");
        }
        else {
            if (getLink() != null) {
                String link = getLink();
                if (!link.equals(plainTextContent)) {
                    fileout.write(plainTextContent + " ");
                }
                fileout.write("<" + link + ">");
            }
            else {
                fileout.write(plainTextContent);
            }
        }

        fileout.write("\n");
        // fileout.write(System.getProperty("line.separator"));
        // fileout.newLine();

        // ^ One would rather expect here one of the above commands
        // commented out. However, it does not work as expected on
        // Windows. My unchecked hypothesis is, that the String Java stores
        // in Clipboard carries information that it actually is \n
        // separated string. The current coding works fine with pasting on
        // Windows (and I expect, that on Unix too, because \n is a Unix
        // separator). This method is actually used only for pasting
        // purposes, it is never used for writing to file. As a result, the
        // writing to file is not tested.

        // Another hypothesis is, that something goes astray when creating
        // StringWriter.

        saveChildrenText(fileout, depth);
    }

    private void saveChildrenText(Writer fileout, int depth) throws IOException {
        for (ListIterator e = childrenUnfolded(); e.hasNext();) {
            final MindMapNodeModel child = (MindMapNodeModel) e.next();
            if (child.isVisible()) {
                child.saveTXT(fileout, depth + 1);
            }
            else {
                child.saveChildrenText(fileout, depth);
            }
        }
    }

    public void collectColors(HashSet colors) {
        if (color != null) {
            colors.add(getColor());
        }
        for (ListIterator e = childrenUnfolded(); e.hasNext();) {
            ((MindMapNodeModel) e.next()).collectColors(colors);
        }
    }

    private String saveRFT_escapeUnicodeAndSpecialCharacters(String text) {
        int len = text.length();
        StringBuffer result = new StringBuffer(len);
        int intValue;
        char myChar;
        for (int i = 0; i < len; ++i) {
            myChar = text.charAt(i);
            intValue = (int) text.charAt(i);
            if (intValue > 128) {
                result.append("\\u").append(intValue).append("?");
            }
            else {
                switch (myChar) {
                case '\\':
                    result.append("\\\\");
                    break;
                case '{':
                    result.append("\\{");
                    break;
                case '}':
                    result.append("\\}");
                    break;
                case '\n':
                    result.append(" \\line ");
                    break;
                default:
                    result.append(myChar);
                }
            }
        }
        return result.toString();
    }

    public void saveRTF(Writer fileout, int depth, HashMap colorTable)
            throws IOException {
        String pre = "{" + "\\li" + depth * 350;
        String level;
        if (depth <= 8) {
            level = "\\outlinelevel" + depth;
        }
        else {
            level = "";
        }
        String fontsize = "";
        if (color != null) {
            pre += "\\cf" + ((Integer) colorTable.get(getColor())).intValue();
        }

        if (isItalic()) {
            pre += "\\i ";
        }
        if (isBold()) {
            pre += "\\b ";
        }
        if (font != null && font.getSize() != 0) {
            fontsize = "\\fs" + Math.round(1.5 * getFont().getSize());
            pre += fontsize;
        }

        pre += "{}"; // make sure setting of properties is separated from the text itself

        fileout.write("\\li" + depth * 350 + level + "{}");
        if (this.toString().matches(" *")) {
            fileout.write("o");
        }
        else {
			String text = saveRFT_escapeUnicodeAndSpecialCharacters(
					this.getPlainTextContent());
			if (getLink() != null) {
                String link = saveRFT_escapeUnicodeAndSpecialCharacters(getLink());
                if (link.equals(this.toString())) {
                    fileout.write(pre + "<{\\ul\\cf1 " + link + "}>" + "}");
                }
                else {
                    fileout.write("{" + fontsize + pre + text + "} ");
                    fileout.write("<{\\ul\\cf1 " + link + "}}>");
                }
            }
            else {
                fileout.write(pre + text + "}");
            }
        }

        fileout.write("\\par");
        fileout.write("\n");

        saveChildrenRTF(fileout, depth, colorTable);
    }

    private void saveChildrenRTF(Writer fileout, int depth, HashMap colorTable)
            throws IOException {
        for (ListIterator e = childrenUnfolded(); e.hasNext();) {
            final MindMapNodeModel child = (MindMapNodeModel) e.next();
            if (child.isVisible()) {
                child.saveRTF(fileout, depth + 1, colorTable);
            }
            else {
                child.saveChildrenRTF(fileout, depth, colorTable);
            }
        }
    }

	public boolean isWriteable() {
		return true;
	}
}
